package com.zmn.plat.business.impl.channel;

import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.plat.business.interfaces.channel.ChannelServProductBService;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.manager.dictionary.ProductDict;
import com.zmn.plat.model.entity.category.BaseCategory;
import com.zmn.plat.model.entity.channel.ChannelServProduct;
import com.zmn.plat.model.entity.channel.product.map.ChannelProductMap;
import com.zmn.plat.model.entity.channel.product.map.ChannelProductMapQuery;
import com.zmn.plat.model.entity.product.ChannelProductQuery;
import com.zmn.plat.model.entity.product.ServProductQuery;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.model.vo.channel.ChannelServProductVO;
import com.zmn.plat.model.vo.channel.ChannelServiceAreaProductCategoryVo;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.channel.ChannelServProductService;
import com.zmn.plat.services.interfaces.channel.ChannelServiceCategoryService;
import com.zmn.plat.services.interfaces.channel.generalproduct.ChannelGeneralProductSwitchService;
import com.zmn.plat.services.interfaces.channel.product.map.ChannelProductMapService;
import com.zmn.plat.services.interfaces.product.ServProductRelationService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;
import com.zmn.plat.services.interfaces.servcategory.ShowCategoryAssociationService;
import com.zmn.plat.utils.bean.BeanCopyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 描述: 渠道服务产品表业务接口类实现
 *
 * @author jiafei
 * @version 1.0
 * @since 2021/6/24 17:59
 */
@Slf4j
@Service
public class ChannelServProductBServiceImpl implements ChannelServProductBService {

	@Resource
	private ServCategoryService servCategoryService;

	@Resource
	private BaseCategoryService baseCategoryService;

	@Resource
	private ShowCategoryAssociationService showCategoryAssociationService;

	@Resource
	private ChannelGeneralProductSwitchService channelGeneralProductSwitchService;

	@Resource
	private ServProductRelationService servProductRelationService;

	@Resource
	private ChannelServiceCategoryService channelServiceCategoryService;

	@Resource
	private ChannelServProductService channelServProductService;

	@Resource
	private ServProductService servProductService;

	@Resource
	protected ChannelProductMapService channelProductMapService;

	@Override
	public List<ChannelServProductVO> listChannelServProductByQuery(ChannelProductQuery query) {

		// 查询前台或后台产品列表
		ServProductQuery servProductQuery = new ServProductQuery();
		BeanCopyUtils.copyProperties(query, servProductQuery);
		servProductQuery.setChannelId(null);
		servProductQuery.setStatus(GlobalConsts.YES);
		List<ChannelServProductVO> servProducts = servProductService.listChannelServProductByQuery(servProductQuery);

		// 查询所有的服务 - 并根据id转为map
		Map<Integer, ServCategory> servCategoryMap = Optional.ofNullable(servCategoryService.listServCategoryAll())
															 .orElse(Collections.emptyList())
															 .stream()
															 .collect(Collectors.toMap(ServCategory::getCategId,
																					   Function.identity()));

		// 查询所有产品分类(id和产品名称) - 并根据id转为map
		Map<Integer, String> baseCategoryMap = Optional.ofNullable(baseCategoryService.listAll())
													   .orElse(Collections.emptyList())
													   .stream()
													   .collect(Collectors.toMap(BaseCategory::getCategId,
																				 BaseCategory::getName));

		// 查询所有的渠道产品 - 并根据产品id转为map
		Map<Integer, Integer> channelServProductList = Optional.ofNullable(
				channelServProductService.listProductIdByChannelId(query.getChannelId())).orElse(
				Collections.emptyList()).stream().collect(Collectors.toMap(ChannelServProduct::getProductId,
																		   ChannelServProduct::getStatus,
																		   (existing, replacement) -> existing));

		// 数据筛选  根据ShowType判断查询的产品是前台还是后台数据
		List<ChannelServProductVO> channelServProductVOS = Objects.equals(query.getShowType(),
																		  ProductConsts.ERP_PRODUCT_TYPE)
				? filterProduct(query, servProducts, servCategoryMap, baseCategoryMap, channelServProductList)
				: filterShowProduct(query, servProducts, servCategoryMap, baseCategoryMap, channelServProductList);

		// 渠道映射产品
		if (NumberUtil.isPositiveInteger(query.getMapStatus())) {
			ChannelProductMapQuery channelProductMapQuery = new ChannelProductMapQuery();
			channelProductMapQuery.setChannelId(query.getChannelId());
			List<ChannelProductMap> channelProductMaps = channelProductMapService.listByQuery(channelProductMapQuery);
			Map<Integer, ChannelProductMap> productMapMap = channelProductMaps.stream().collect(
					Collectors.toMap(ChannelProductMap::getProductId, Function.identity(), (x, y) -> x));

			// 所有没有映射的产品
			List<ChannelServProductVO> collect = channelServProductVOS.stream().filter(x -> {
				ChannelProductMap channelProductMap = productMapMap.get(x.getProductId());
				if (Objects.isNull(channelProductMap)) {
					return true;
				}
				return StringUtil.isBlank(channelProductMap.getChannelProductSubId()) && StringUtil.isBlank(
						channelProductMap.getChannelProductParentId());

			}).collect(Collectors.toList());

			//
			if (Objects.equals(query.getMapStatus(), 1)) {
				// 渠道映射是
				channelServProductVOS.removeAll(collect);
			} else {
				// 渠道映射否
				channelServProductVOS = collect;
			}
		}
		return channelServProductVOS;
	}

	/**
	 * 描述: 后台类型数据筛选
	 *
	 * @param channelServProductVOS channelServProductVOS
	 * @author jiafei
	 * @since 2021/6/25 14:34
	 */
	@SuppressWarnings("Duplicates")
	private List<ChannelServProductVO> filterProduct(ChannelProductQuery query,
													 List<ChannelServProductVO> channelServProductVOS,
													 Map<Integer, ServCategory> servCategoryMap,
													 Map<Integer, String> baseCategoryMap,
													 Map<Integer, Integer> channelServProductList) {

		// 后台服务分类能关联的前台分类的数据
		List<String> categoryAssociationsIds =
				Optional.ofNullable(showCategoryAssociationService.listByChannelAndShowType(query.getChannelId(),
																							ProductConsts.EC_PRODUCT_TYPE))
						.orElse(Collections.emptyList())
						.stream()
						.map(t -> t.getServCategId() + "_" + t.getCategId()).collect(Collectors.toList());

		// 查询所有禁用了的通用产品所属服务分类id
		List<Integer> channelGeneralProductServCateIds = channelGeneralProductSwitchService
				.listServCateIdByChannelAndStatus(query.getChannelId(), GlobalConsts.NO);

		// 查询所有前台产品能与后台产品关联的产品id
		List<Integer> servProductIds = servProductRelationService.listProductIdByServProductStatus(GlobalConsts.YES);

		// 筛选数据
		return channelServProductVOS.stream().filter(item -> {

			// 判断后台分类是否可以关联到前台分类
			boolean showCategoryAssociationsIdContains = categoryAssociationsIds.contains(
					item.getServCategId() + "_" + item.getCategId());
			if (!showCategoryAssociationsIdContains) {
				return false;
			}

			// 判断产品是否为通用产品
			boolean isGeneralProduct = Objects.equals(ProductDict.CURRENCY_PRODUCT, item.getProductType());

			// 判断产品的服务分类id 是否禁用
			boolean generalProductContains = channelGeneralProductServCateIds.contains(item.getServCategId());

			// 是通用产品且禁用
			if (isGeneralProduct && generalProductContains) {
				return false;
			}

			// 不是通用产品 则判断是否为当前查询渠道产品
			if (!isGeneralProduct && !Objects.equals(item.getChannelId(), query.getChannelId())) {
				return false;
			}

			if (!servProductIds.contains(item.getProductId())) {
				return false;
			}

			// 渠道产品状态是否为禁用
			Integer status = channelServProductList.get(item.getProductId());

			// 设置开通状态
			if (Objects.isNull(status)) {
				item.setStatus(GlobalConsts.YES);
			} else {
				item.setStatus(status);
			}

			// 查询状态不为空 渠道产品状态不为空 则判断出渠道产品状态
			if (!Objects.isNull(query.getStatus())
				&& !Objects.isNull(status)
				&& !Objects.equals(query.getStatus(), status)) {

				// 判断与查询状态是否一致
				return false;
			}

			// 查询状态不为空 渠道状态为空 则判断产品状态
			if (!Objects.isNull(query.getStatus())
				&& Objects.isNull(status)
				&& !Objects.equals(query.getStatus(), GlobalConsts.YES)) {

				// 判断与查询状态是否一致
				return false;
			}


			return productCateName(servCategoryMap, baseCategoryMap, item);
		}).collect(Collectors.toList());
	}

	/**
	 * 描述: 前台类型数据筛选
	 *
	 * @param channelServProductVOS channelServProductVOS
	 * @author jiafei
	 * @since 2021/6/25 14:34
	 */
	@SuppressWarnings("Duplicates")
	private List<ChannelServProductVO> filterShowProduct(ChannelProductQuery query,
														 List<ChannelServProductVO> channelServProductVOS,
														 Map<Integer, ServCategory> servCategoryMap,
														 Map<Integer, String> baseCategoryMap,
														 Map<Integer, Integer> channelServProductList) {

		// 判断前台分类是否可以关联到后台分类
		List<ChannelServiceAreaProductCategoryVo> channelServiceCategories =
				channelServiceCategoryService.listByChannelIdAndShowType(query.getChannelId(),
																		 ProductConsts.EC_PRODUCT_TYPE);
		if (CollectionUtil.isNullOrEmpty(channelServiceCategories)) {
			return Collections.emptyList();
		}

		// 根据服务分类id+"_"+二级产品id筛选
		List<String> serviceProductCategory = channelServiceCategories.stream()
																	  .map(t -> t.getServCategId() + "_" +
																				t.getCategId())
																	  .collect(Collectors.toList());
		if (CollectionUtil.isNullOrEmpty(serviceProductCategory)) {
			return Collections.emptyList();
		}

		// 查询渠道开通的通用产品id 和 状态开启的渠道产品
		List<Integer> validGeneralProductIds =
				Optional.ofNullable(servProductRelationService.listProductIdByChannelIdAndStatus(query.getChannelId(),
																								 GlobalConsts.YES))
						.orElse(Collections.emptyList());

		return channelServProductVOS.stream().filter(item -> {

			// 判断产品产品所属服务前后台是否关联
			boolean serviceProductCategoryContains = serviceProductCategory.contains(
					item.getServCategId() + "_" + item.getCategId());
			if (!serviceProductCategoryContains) {
				return false;
			}

			// 判断是否选中通用产品 或者为开通的渠道产品
			if (!validGeneralProductIds.contains(item.getProductId())) {
				return false;
			}

			// 渠道产品状态是否为禁用
			Integer status = channelServProductList.get(item.getProductId());

			// 设置开通状态
			if (Objects.isNull(status)) {
				item.setStatus(GlobalConsts.YES);
			} else {
				item.setStatus(status);
			}

			// 查询状态不为空 渠道产品状态不为空 则判断出渠道产品状态
			if (!Objects.isNull(query.getStatus())
				&& !Objects.isNull(status)
				&& !Objects.equals(query.getStatus(), status)) {

				// 判断与查询状态是否一致
				return false;
			}

			// 查询状态不为空 渠道状态为空 则判断产品状态
			if (!Objects.isNull(query.getStatus())
				&& Objects.isNull(status)
				&& !Objects.equals(query.getStatus(), GlobalConsts.YES)) {

				// 判断与查询状态是否一致
				return false;
			}

			return productCateName(servCategoryMap, baseCategoryMap, item);
		}).collect(Collectors.toList());
	}

	/**
	 * 描述: 设置产品名称
	 * 服务名称 一级产品名称 二级产品名称
	 *
	 * @param servCategoryMap servCategoryMap
	 * @param baseCategoryMap baseCategoryMap
	 * @param item            item
	 * @return boolean
	 * @author jiafei
	 * @since 2021/6/30 16:27
	 */
	private boolean productCateName(Map<Integer, ServCategory> servCategoryMap,
									Map<Integer, String> baseCategoryMap,
									ChannelServProductVO item) {

		// 产品服务分类名称
		ServCategory servCategory = servCategoryMap.get(item.getServCategId());
		if (Objects.nonNull(servCategory)) {
			String servCateName = Objects.equals(item.getShowType(), ProductConsts.ERP_PRODUCT_TYPE) ?
					servCategory.getName() : servCategory.getShowName();
			item.setServCategName(servCateName);
		}

		// 产品一级分类名称
		String cateOneProductName = baseCategoryMap.get(item.getCategOneId());
		if (Objects.nonNull(cateOneProductName)) {
			item.setCategOneName(cateOneProductName);
		}

		// 产品二级分类名称
		String cateTwoProductName = baseCategoryMap.get(item.getCategId());
		if (Objects.nonNull(cateTwoProductName)) {
			item.setCategName(cateTwoProductName);
		}

		return true;
	}

}
